/***
 * @Description: 本文件是应用文件，使用操作系统自带的API进行ping操作的实现，主要定义ping函数的调用接口和数据结构
 * @Author: Liverpool
 * @Date: 2024-08-08 00:50:47
 * @LastEditTime: 2024-08-08 00:51:04
 * @LastEditors: Liverpool
 */
#ifndef PING_H
#define PING_H

#include <stdint.h>
#include "time.h"

#define PING_SOCKET_MODE 0 // 设置ping模式的socket通信方式，有0或1选择，没有本质区别，只有socket实现函数的不同

#define PING_BUFFER_SIZE 4096
#define IP_ADDR_SIZE 4

#define PING_REQUEST_HEADER_TYPE 8   // ICMP协议的ping请求的头的type值
#define PING_REQUEST_HEADER_CODE 0   // ICMP协议的ping请求的头的code值
#define PING_REQUEST_HEADER_ID 0x300 // ICMP协议的ping请求的头的ID值

#pragma pack(1) // 设置字节对齐为1

// IP数据报首部的数据结构定义
typedef struct _ip_hdr
{
    // 协议栈是小端存储
    uint16_t header_size : 4;      // IP数据报的包头长度
    uint16_t version : 4;          // IP数据报的协议类型
    uint16_t tos : 8;              // IP数据报的区分服务
    uint16_t total_len;            // 总长度
    uint16_t Id;                   // 标识
    uint16_t offset : 13;          // 偏移地址，8字节为单位
    uint16_t more_flag : 1;        // 是否还有分片
    uint16_t disable_flag : 1;     // 是否分片
    uint16_t reversed : 1;         //  预留
    uint8_t ttl;                   // 生存时间
    uint8_t protocol;              // 数据部分的协议
    uint16_t header_checksum;      // 首部的校验和
    uint8_t src_ip[IP_ADDR_SIZE];  // 源地址
    uint8_t dest_ip[IP_ADDR_SIZE]; // 目的地址
} D_ip_hdr;

// 定义ICMPv4协议数据的包头部分
typedef struct _icmp_hdr
{
    uint8_t type;      // 类型
    uint8_t code;      // 代码
    uint16_t checksum; // 整个数据包的校验和
    uint16_t id;
    uint16_t seq;
} D_icmp_hdr;
#pragma pack()

// 定义ping的ICMP请求的数据包，操作系统会自动填充IP协议头，所以不需要定义
typedef struct _echo_request
{
    D_icmp_hdr echo_hdr;
    char echo_buf[PING_BUFFER_SIZE];
} D_echo_request;

// 定义ping的ICMP回应的数据包，回应的数据包会带上IP数据头，所以需要进行解析
typedef struct _echo_reply
{
    D_ip_hdr ip_hdr;
    D_icmp_hdr echo_hdr;
    char echo_buf[PING_BUFFER_SIZE];
} D_echo_reply;

// 定义ping的数据结构，包括request和reply
typedef struct _ping
{
    D_echo_request request;
    D_echo_reply reply;
} D_ping;

void ping_run(D_ping *ping, const char *dest, int count, int size, int interval); // ping函数运行命令
#endif                                                                            // !PING_H